﻿using System;
using System.Xml;
using System.Xml.Schema;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace WITD
{
    /// <summary>
    /// A Window class for interacting with team project categories.
    /// </summary>
    public partial class Categories : Window
    {

        const String DefaultHeader = " (Default)";
        const String WITTrailer = " work item type";

        WorkItemCategory CategoryManager;
        WorkItemTypeDef WIManager;
        WorkItemStore Store;
        Project CurrentProject;
        CategoryCollection CategoriesList;
        bool CategorySelected = false;
        bool DefaultWITSelected = false;
        String SelectedCategory;
        String SelectedWIT;
        Opaque hider;
        Window toolWindow;
        bool _didRename = false;
        bool _didDestroy = false;
        bool _didImport = false;
        bool _didExport = false;

        /// <summary>
        /// Denotes whether a rename was successful or not.
        /// </summary>
        public bool DidRename
        {
            get
            {
                return _didRename;
            }
        }

        /// <summary>
        /// Denotes whether a destroy was successful or not.
        /// </summary>
        public bool DidDestroy
        {
            get
            {
                return _didDestroy;
            }
        }

        /// <summary>
        /// Denotes whether a rename was successful or not.
        /// </summary>
        public bool DidImport
        {
            get
            {
                return _didImport;
            }
        }

        /// <summary>
        /// Denotes whether a destroy was successful or not.
        /// </summary>
        public bool DidExport
        {
            get
            {
                return _didExport;
            }
        }

        /// <summary>
        /// Constructor for this window.
        /// </summary>
        /// <param name="store">The WorkItemStore instance to use.</param>
        /// <param name="projectName">The name of the team project to manage.</param>
        /// <param name="parent">The owning Window object instance. It must have been shown at least once to avoid an Exception.</param>
        public Categories(WorkItemStore store, String projectName, Window parent)
        {
            InitializeComponent();
            
            Store = store;
            this.Title = "Category and WITD Management: Project: " + projectName;
            Owner = parent;
            CurrentProject = Store.Projects[projectName];
            CategoryManager = new WorkItemCategory(CurrentProject);
            WIManager = new WorkItemTypeDef();
            PopulateCategories();
            PopulateWorkItemTypes();

            hider = new Opaque(this);
        }

        /// <summary>
        /// Populates the TreeView containing the categories and respective work item types.
        /// </summary>
        private void PopulateCategories()
        {
            bool isDefault = false;
            CategoriesList = CategoryManager.GetCategories(CurrentProject);
            tvCategories.Items.Clear();

            if (CategoriesList != null && CategoriesList.Count > 0)
            {
                foreach (Category cat in CategoriesList)
                {
                    TreeViewItem item = new TreeViewItem();
                    item.Header = cat.Name;
                    item.Tag = "CAT";
                    item.DisplayMemberPath = "Name";
    
                    foreach (WorkItemType wit in cat.WorkItemTypes)
                    {
                        isDefault = false;
                        TreeViewItem witItem = new TreeViewItem();
                        witItem.Header = wit.Name;
                        witItem.DisplayMemberPath = "Name";
                        if (cat.DefaultWorkItemType.Name == wit.Name)
                        {
                            isDefault = true;
                            witItem.Header = witItem.Header + DefaultHeader;
                            witItem.Tag = "DEF";
                            witItem.Foreground = Brushes.Red;
                            witItem.FontWeight = FontWeights.Bold;
                        }
                        else
                        {
                            witItem.Header = witItem.Header;
                            witItem.Tag = "WIT";
                            witItem.Foreground = Brushes.Black;
                            witItem.FontWeight = FontWeights.Normal;
                        }
                        if (isDefault)
                        {
                            item.Items.Insert(0, witItem);
                        }
                        else
                        {
                            item.Items.Add(witItem);
                        }
                    }
                    tvCategories.Items.Add(item);
                }
            }
            tvCategories.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("Header", System.ComponentModel.ListSortDirection.Ascending));
        }

    

        /// <summary>
        /// Populates the TreeView containing the categories and respective work item types.
        /// </summary>
        /// <param name="project">The project for which to display the categories and respective work item types.</param>
        private void PopulateCategories(Project project)
        {
            bool isDefault = false;
            CategoriesList = CategoryManager.GetCategories(project);
            tvCategories.Items.Clear();

            if (CategoriesList != null && CategoriesList.Count > 0)
            {
                foreach (Category cat in CategoriesList)
                {
                    TreeViewItem item = new TreeViewItem();
                    item.Header = cat.Name;
                    item.Tag = "CAT";
                    item.DisplayMemberPath = "Name";
  
                    foreach (WorkItemType wit in cat.WorkItemTypes)
                    {
                        isDefault = false;
                        TreeViewItem witItem = new TreeViewItem();
                        witItem.Header = wit.Name;
                        witItem.DisplayMemberPath = "Name";
                        if (cat.DefaultWorkItemType.Name == wit.Name)
                        {
                            isDefault = true;
                            witItem.Header = witItem.Header + DefaultHeader;
                            witItem.Tag = "DEF";
                            witItem.Foreground = Brushes.Red;
                            witItem.FontWeight = FontWeights.Bold;
                        }
                        else
                        {
                            witItem.Header = witItem.Header;
                            witItem.Tag = "WIT";
                            witItem.Foreground = Brushes.Black;
                            witItem.FontWeight = FontWeights.Normal;
                        }
                        if (isDefault)
                        {
                            item.Items.Insert(0, witItem);
                        }
                        else
                        {
                            item.Items.Add(witItem);
                        }
                       
                        item.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("Header", System.ComponentModel.ListSortDirection.Ascending));
                    }
                    tvCategories.Items.Add(item);
                }
            }
            tvCategories.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("Header", System.ComponentModel.ListSortDirection.Ascending));

            if (!String.IsNullOrEmpty(SelectedCategory))
            {
                ExpandCategory(SelectedCategory);
            }
        }

        /// <summary>
        /// Selects and expands the last selected category in the <see cref="tvCategories">tvCategories TreeView control</see>.
        /// </summary>
        /// <param name="categoryName">The name of the last selected category in the TreeView control.</param>
        private void ExpandCategory(String categoryName)
        {
            foreach (TreeViewItem item in tvCategories.Items)
            {
                if (item.Header.ToString() == categoryName)
                {
                    item.ExpandSubtree();
                    item.IsSelected = true;
                    return;
                }
            }
        }

        /// <summary>
        /// Removes the tags from work item type and category names for subsequent comparison.
        /// </summary>
        /// <param name="name">The text to normalize.</param>
        /// <returns>The normalized text.</returns>
        private String NormalizeName(String name)
        {
            if (name.Contains(WITTrailer))
            {
                name = name.Replace(WITTrailer, "");
            }

            if (name.Contains(DefaultHeader))
            {
                name = name.Replace(DefaultHeader, "");
            }

            name = name.Trim();

            return name;
        }

        /// <summary>
        /// Populates the ListBox displaying the available work item types.
        /// </summary>
        /// <param name="project">The project to get the available work item types for.</param>
        public void PopulateWorkItemTypes(Project project)
        {
            lstWorkItemTypes.Items.Clear();

            foreach (WorkItemType wit in project.WorkItemTypes)
            {
                ListViewItem item = new ListViewItem();
                item.Content = wit.Name; 
                lstWorkItemTypes.Items.Add(item);
            }
            lstWorkItemTypes.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("Content", System.ComponentModel.ListSortDirection.Ascending));
        }

        /// <summary>
        /// Populates the ListBox displaying the available work item types.
        /// </summary>
        public void PopulateWorkItemTypes()
        {
            lstWorkItemTypes.Items.Clear();

            foreach (WorkItemType wit in CurrentProject.WorkItemTypes)
            {
                ListViewItem item = new ListViewItem();
                item.Content = wit.Name;
                lstWorkItemTypes.Items.Add(item);
            }
            lstWorkItemTypes.Items.SortDescriptions.Add(new System.ComponentModel.SortDescription("Content", System.ComponentModel.ListSortDirection.Ascending));
        }

        /// <summary>
        /// Closes this window.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// Gets the reference name for the selected category.
        /// </summary>
        /// <param name="categoryName">The name of the category for which to get the reference name.</param>
        /// <returns>The reference name of the specified category name, if the category exists in the current project. Otherwise an empty String.</returns>
        private String GetRefName(String categoryName)
        {
            if (CategorySelected)
            {
                try
                {
                    return CategoryManager.GetRefName(categoryName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
            return String.Empty;
        }
        
        /// <summary>
        /// Captures the selected work item type and its category.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void tvCategories_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            txtRefNameForSelectedCat.Text = String.Empty;

            if (tvCategories.SelectedItem != null)
            {
                TreeViewItem node = tvCategories.SelectedItem as TreeViewItem;
                if ((string)(tvCategories.SelectedItem as TreeViewItem).Tag == "CAT")
                {
                    CategorySelected = true;
    
                    DefaultWITSelected = false;
                    SelectedCategory = (tvCategories.SelectedItem as TreeViewItem).Header.ToString();
                    txtRefNameForSelectedCat.Text = GetRefName(SelectedCategory);
                }
                else
                {
                    SelectedCategory = GetCategoryForSelectedWIT(node.Header.ToString(), GetIndexOfSelectedWIT(node.Header.ToString()));
                    txtRefNameForSelectedCat.Text = GetRefName(SelectedCategory);
                    if ((string)(tvCategories.SelectedItem as TreeViewItem).Tag == "DEF")
                    {
                        CategorySelected = false;

                        DefaultWITSelected = true;
                        SelectedCategory = "";
                    }
                    else
                    {
                        CategorySelected = false;
                       
                        DefaultWITSelected = false;
                        SelectedCategory = "";
                    }
                }
            }
        }

        /// <summary>
        /// Determines the index of the TreeViewItem that is the category for the selected work item type.
        /// </summary>
        /// <param name="wit">The name of the selected work item type.</param>
        /// <returns>The index of the category to which the selected work item type belongs.</returns>
        private Int32 GetIndexOfSelectedWIT(String wit)
        {
            Int32 location = -1;

            for (int i = 0; i < tvCategories.Items.Count; i++)
            {
                TreeViewItem catNode = (tvCategories.Items[i] as TreeViewItem);
                for (int j = 0; j < catNode.Items.Count; j++)
                {
                    TreeViewItem witNode = catNode.Items[j] as TreeViewItem;
                    if (NormalizeName(witNode.Header.ToString()) == NormalizeName(wit) && witNode.IsSelected)
                    {
                        location = i;
                        return location;
                    }
                }
            }

            return location;
        }

        /// <summary>
        /// Determines the category for the selected work item type.
        /// </summary>
        /// <param name="wit">The name of the selected work item type.</param>
        /// <param name="location">The relative index of the selected work item type.</param>
        /// <returns>The category to which the selected work item type belongs.</returns>
        private String GetCategoryForSelectedWIT(String wit, Int32 location)
        {    
            //find catNode with tag == "CAT" with highest index less than index of wit, at location
            String currentCategory = String.Empty;

            for (int i = 0; i < tvCategories.Items.Count; i++)
            {
                TreeViewItem catNode = (tvCategories.Items[i] as TreeViewItem);
                currentCategory = NormalizeName(catNode.Header.ToString());

                for (int j = 0; j < catNode.Items.Count; j++)
                {
                    TreeViewItem witNode = catNode.Items[j] as TreeViewItem;
                    if (NormalizeName(witNode.Header.ToString()) == NormalizeName(wit) && witNode.IsSelected)
                    {
                        if (location == i)
                        {
                            return currentCategory;
                        }
                    }
                }
            }

            return currentCategory;
        }

        /// <summary>
        /// Removes a work item type (wit) from the specified category. <para></para><para></para>
        /// If the specified wit is the default, then the first non-default wit is made the new default. The number of wit's in the category 
        /// decreases by one.
        /// </summary>
        /// <param name="categoryName">The category from which to remove the specified work item type.</param>
        /// <param name="witName">The work item type to remove.</param>
        private void RemoveWIT(String categoryName, String witName)
        {
            String message;
            Int32 witCount = 0;
            bool? result = false;
            bool success;
            
            witCount = CategoryManager.GetCategoryWITCount(categoryName);
            if (DefaultWITSelected)
            {
                //check if there is at least one more wit in category
                if (witCount == 2)
                {
                    //make other work item type the new default
                    Category cat = CurrentProject.Categories[categoryName];
                    foreach (WorkItemType wit in cat.WorkItemTypes)
                    {
                        if (wit.Name != cat.DefaultWorkItemType.Name)
                        {
                            try
                            {
                                //make this the new default, then remove the other
                                //edit the XML
                                SetCursor(Cursors.Wait);
                                ObscureMainWindow(null);

                                success = CategoryManager.ReplaceDefaultWITForCategory(cat.Name, wit.Name, false, out message);
                                if (!success)
                                {
                                    ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                                }
                                else
                                    PopulateCategories(CurrentProject);
                                return;
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                            }
                            finally
                            {
                                SetCursor(Cursors.Arrow);
                                UnobscureMainWindow();
                            }
                        }
                    }
                }
                else
                {
                    if (witCount == 1)
                    {
                        MessageBox.Show("Error: Category cannot be empty. Add another WITD to the " + categoryName.Replace("Default:", "").Replace("work item type", "").Trim() + " category");
                    }
                    else
                    {
                        try
                        {
                            ChooseNewDefaultWIT witSelector = new ChooseNewDefaultWIT(CurrentProject, categoryName, witName, this);
                            ObscureMainWindow(witSelector);

                            result = witSelector.ShowDialog();
                            if (result == true)
                            {
                                try
                                {
                                    //make this the new default, then remove the other
                                    //edit the XML
                                    SetCursor(Cursors.Wait);
                                    String newDefaultWIT = witSelector.SelectedWITToReplaceDefault;
                                    success = CategoryManager.ReplaceDefaultWITForCategory(categoryName, newDefaultWIT, false, out message);
                                    if (!success)
                                    {
                                        ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                                    }
                                    else
                                        PopulateCategories(CurrentProject);
                                    return;
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                                }
                                finally
                                {
                                    SetCursor(Cursors.Arrow);
                                }
                            }
                        }
                        finally
                        {
                            UnobscureMainWindow();
                        }
                    }
                }
            }
            else
            {
                try
                {
                    //not default selected
                    SetCursor(Cursors.Wait);
                    ObscureMainWindow(null);

                    success = CategoryManager.RemoveWITFromCategory(CurrentProject, categoryName, witName, out message);
                    if (!success)
                    {
                        ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                    }
                    else
                        PopulateCategories(CurrentProject);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                finally
                {
                    SetCursor(Cursors.Arrow);
                    UnobscureMainWindow();
                }
            }
        }

        /// <summary>
        /// Removes a WIT from the selected category. Calls the RemoveWIT method.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRemoveWIT_Click(object sender, RoutedEventArgs e)
        {
            //get category of selected wit
            if (tvCategories.SelectedItem != null)
            {
                if (!CategorySelected)
                {
                    String selectedWIT = NormalizeName((tvCategories.SelectedItem as TreeViewItem).Header.ToString());
                    Int32 location = GetIndexOfSelectedWIT(selectedWIT);
                    String currentCategory = GetCategoryForSelectedWIT(selectedWIT, location);

                    RemoveWIT(currentCategory, selectedWIT);
                }
                else
                {
                    MessageBox.Show("Error: Please select a WITD to remove.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                
            }
            else
            {
                MessageBox.Show("Error: Please select a WITD to remove.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Calls the AddWIT method to add a new category.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddWIT_Click(object sender, RoutedEventArgs e)
        {
            ArrayList selectedWITs = null; 
            
            if (String.IsNullOrEmpty(SelectedWIT))
            {
                MessageBox.Show("Error: Please select one or more WITDs to add to the selected category.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
            else
            {
                if (String.IsNullOrEmpty(SelectedCategory))
                {
                    MessageBox.Show("Error: Please select a category to which to add the selected WITDs.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                }
                else
                {
                    selectedWITs = new ArrayList();
                    foreach (ListViewItem selectedWIT in lstWorkItemTypes.SelectedItems)
                    {
                        selectedWITs.Add(selectedWIT.Content);
                    }
                    AddWIT(SelectedCategory, selectedWITs);
                }
            }
        }

        /// <summary>
        /// Calls the WorkItemCategory object to add a work item type to the specified category.
        /// </summary>
        /// <param name="categoryName">The category to which to add the work item type.</param>
        /// <param name="witName">The name of the work item type to add.</param>
        private void AddWIT(String categoryName, String witName)
        {
            bool success;
            String message;

            try
            {
                SetCursor(Cursors.Wait);
                ObscureMainWindow(null);

                success = CategoryManager.AddWITToCategory(categoryName, witName, out message);
                

                if (!success)
                {
                    ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                }
                else
                {
                    PopulateCategories(CurrentProject);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                SetCursor(Cursors.Arrow);
                UnobscureMainWindow();
            }
            
        }


        /// <summary>
        /// Calls the WorkItemCategory object to add a work item type to the specified category.
        /// </summary>
        /// <param name="categoryName">The category to which to add the work item type.</param>
        /// <param name="witNames">The names of the work item types to add.</param>
        private void AddWIT(String categoryName, ArrayList witNames)
        {
            bool success;
            String message;

            try
            {
                SetCursor(Cursors.Wait);
                ObscureMainWindow(null);

                success = CategoryManager.AddWITsToCategory(categoryName, witNames, out message);


                if (!success)
                {
                    ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                }
                else
                {
                    PopulateCategories(CurrentProject);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                SetCursor(Cursors.Arrow);
                UnobscureMainWindow();
            }

        }


        /// <summary>
        /// Stores the currently selected work item type.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lstWorkItemTypes_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lstWorkItemTypes.SelectedItem != null)
            {
                SelectedWIT = (lstWorkItemTypes.SelectedItem as ListViewItem).Content.ToString();
            }
        }

        /// <summary>
        /// Calls the AddCategory method to display an input form for creating a new category.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAddCategory_Click(object sender, RoutedEventArgs e)
        {
            AddCategory(CurrentProject);
        }

        /// <summary>
        /// Opens a new form for inputting values for creating a new category.
        /// </summary>
        /// <param name="project">The project to which to add the category.</param>
        private void AddCategory(Project project)
        {
            AddCategory catForm = new AddCategory(project, hider);
            ObscureMainWindow(catForm);

            try
            {
                bool? result = catForm.ShowDialog();

                if (result.Value)
                {
                    if (catForm.Success)
                    {
                        PopulateCategories();
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
            
        }

        /// <summary>
        /// Changes the default work item type for the specified category. Fails if there is only one work item type 
        /// in the category. If there are two work item types, then the non-default becomes the default while the 
        /// original default becomes non-default.
        /// <para></para><para></para>
        /// If there are more than two work item types in the category, a list of the work item types that are in the category are 
        /// displayed for the user to choose from, excluding the current default.
        /// </summary>
        /// <param name="categoryName">The name of the category for which to change the default work item type.</param>
        private void ChangeDefault(String categoryName)
        {
            String message = String.Empty;
            bool success;

            Int32 witCount = CategoryManager.GetCategoryWITCount(categoryName);
            if (witCount == 1)
            {
                MessageBox.Show("Please add additional WITDs to category " + categoryName + " before trying to change the default WITD.", "Error",
                                MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
            else
            {
                if (witCount == 2)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                
                        String newDefault = CategoryManager.GetNonDefaultWIT(categoryName);
                        success = CategoryManager.ReplaceDefaultWITForCategory(categoryName, newDefault, true, out message);
                        if (!success)
                        {
                            ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                        }
                        else
                            PopulateCategories(CurrentProject);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    finally
                    {
                        SetCursor(Cursors.Arrow);
                        Buttons(true);
                    }
                }
                else
                {
                    //more than 2 so prompt
                    ChooseNewDefaultWIT witSelector = new ChooseNewDefaultWIT(CurrentProject, categoryName, CurrentProject.Categories[categoryName].DefaultWorkItemType.Name, hider);
                    try
                    {
                        ObscureMainWindow(witSelector);
                        bool? result = witSelector.ShowDialog();

                        if (result.Value)
                        {
                            try
                            {
                                SetCursor(Cursors.Wait);

                                success = CategoryManager.ReplaceDefaultWITForCategory(categoryName, witSelector.SelectedWITToReplaceDefault, true, out message);
                                if (!success)
                                {
                                    ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                                }
                                else
                                    PopulateCategories(CurrentProject);
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                            }
                            finally
                            {
                               SetCursor(Cursors.Arrow); 
                            }
                        }
                    }
                    finally
                    {
                        UnobscureMainWindow();
                    }
                }
            }
        }

        /// <summary>
        /// Calls method <see cref="ChangeDefault">ChangeDefault()</see> to change the default work item type for the selected category./>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnChangeDefault_Click(object sender, RoutedEventArgs e)
        {
            if (String.IsNullOrEmpty(SelectedCategory))
            {
                MessageBox.Show("Error: Please select a category in which to change the default WITD.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
            else
            {
                ChangeDefault(SelectedCategory);
            }
        }

        /// <summary>
        /// Displays a specified message with the specified calling method name.
        /// </summary>
        /// <param name="message">The message to display.</param>
        /// <param name="caller">The calling method name to display if message is null or empty.</param>
        private void ShowError(String message, String caller)
        {
            if (!String.IsNullOrEmpty(message))
            {
                MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            else
            {
                MessageBox.Show("Error in " + caller + ".", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Sets the mouse cursor to the specified cursor.
        /// </summary>
        /// <param name="newCursor">The new cursor.</param>
        public void SetCursor(Cursor newCursor)
        {
            this.Cursor = newCursor;
        }

        /// <summary>
        /// Removes the specified category from the current project.
        /// </summary>
        /// <param name="categoryName">The name of the category to remove.</param>
        private void RemoveCategory(String categoryName)
        {
            bool success;
            String message;
            try
            {
                SetCursor(Cursors.Wait);

                success = CategoryManager.RemoveCategory(CurrentProject, SelectedCategory, out message);
                if (!success)
                {
                    ShowError(message, System.Reflection.MethodInfo.GetCurrentMethod().Name);
                }
                else
                    PopulateCategories(CurrentProject);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                SetCursor(Cursors.Arrow);
            }
        }

        /// <summary>
        /// Occurs when the Remove Category button is clicked. Calls <see cref="RemoveCategory">RemoveCategory method.</see>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRemoveCategory_Click(object sender, RoutedEventArgs e)
        {
            if (String.IsNullOrEmpty(SelectedCategory) || !CategorySelected)
            {
                MessageBox.Show("Error: Please select a category to remove.", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
            else
            {
                RemoveCategory(SelectedCategory);
            }
        }
                
        /// <summary>
        /// Updates the <see cref="btnImport">Import button</see> caption depending on the checked state of this control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkValidateOnly_Checked(object sender, RoutedEventArgs e)
        {
            if (chkValidateOnly.IsChecked.Value)
            {
                btnImport.Content = "Validate WITD Only";
            }
            else
            {
                btnImport.Content = "Validate & Import WITD";
            }
        }
               
        /// <summary>
        /// Updates the <see cref="btnImport">Import button</see> caption depending on the checked state of this control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chkValidateOnly_Unchecked(object sender, RoutedEventArgs e)
        {
            if (chkValidateOnly.IsChecked.Value)
            {
                btnImport.Content = "Validate WITD Only";
            }
            else
            {
                btnImport.Content = "Validate & Import WITD";
            }
        }

        /// <summary>
        /// Renames the selected WIT. Opens a form to enter the new WIT name.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRename_Click(object sender, RoutedEventArgs e)
        {
            if (lstWorkItemTypes.SelectedItem != null)
            {
                if (lstWorkItemTypes.SelectedItems.Count != 1)
                {
                    MessageBox.Show("You may select only one WITD to rename.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                else
                {
                    RenameWIT(SelectedWIT);
                }
            }
            else
            {
                MessageBox.Show("You must select a WITD to rename.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Attempts to rename the specified work item type. Displays a form for the user to type in a new name.
        /// </summary>
        /// <param name="witName">The name of the work item type to rename.</param>
        private void RenameWIT(String witName)
        {
            bool? result;
            String message;
            _didRename = false;

            NewWITName newWITNameForm = new NewWITName(witName, hider);
            ObscureMainWindow(newWITNameForm);

            try
            {
                result = newWITNameForm.ShowDialog();
                if (result == true)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);

                        WIManager.RenameWITD(CurrentProject.Store.TeamProjectCollection.Uri.ToString(), CurrentProject.Name, witName, newWITNameForm.NewName, out message);

                        if (!String.IsNullOrEmpty(message))
                        {
                            MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                        else
                        {
                            _didRename = true;
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error renaming WITD " + witName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    finally
                    {
                        if (_didRename)
                        {
                            SyncReconnect();
                        }

                        Buttons(true);
                        SetCursor(Cursors.Arrow);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Attempts to destroy selected WITDs.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDestroyWIT_Click(object sender, RoutedEventArgs e)
        {
            String witsToDestroy = "";
            
            if (lstWorkItemTypes.SelectedItem != null)
            {
                Buttons(false);
                SetCursor(Cursors.Wait);
                ObscureMainWindow(null);

                ArrayList wits = new ArrayList();
                foreach (ListViewItem wit in lstWorkItemTypes.SelectedItems)
                {
                    wits.Add(wit.Content);
                    witsToDestroy += wit.Content + ", ";
                }
                witsToDestroy = witsToDestroy.Trim().TrimEnd(',');
                if (MessageBox.Show("Are you sure you want to destroy these WITDs?" + Environment.NewLine +
                                    witsToDestroy, "Destroy WITDs", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    DestroyWITDs(wits);
                    PopulateWorkItemTypes();
                }
                Buttons(true);
                SetCursor(Cursors.Arrow);
                UnobscureMainWindow();
            }
            else
            {
                MessageBox.Show("You must select one or more WITDs to destroy.", "Select WITDs to destroy", MessageBoxButton.OK, MessageBoxImage.Information);
            }
        }

        /// <summary>
        /// Destroys the specified work item type. Fails if the work item type is contained in one or more categories.
        /// </summary>
        /// <param name="witName">The name of the work item type to destroy.</param>
        private void DestroyWITD(String witName)
        {
            String message;
            _didDestroy = false;

            try
            {
                SetCursor(Cursors.Wait);
                Buttons(false);

                _didDestroy = false;
                WIManager.DestroyWITD(CurrentProject.Store.TeamProjectCollection.Uri.ToString(), CurrentProject.Name, witName, out message);
                if (!String.IsNullOrEmpty(message))
                {
                    MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                else
                {
                    _didDestroy = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error destroying WITD " + witName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
            finally
            {
                if (_didDestroy)
                {
                    SyncReconnect();
                    PopulateWorkItemTypes();
                }

                SetCursor(Cursors.Arrow);
            }
        }


        /// <summary>
        /// Destroys the specified work item types. Fails if the work item type is contained in one or more categories.
        /// </summary>
        /// <param name="witNames">The names of the work item types to destroy.</param>
        private void DestroyWITDs(ArrayList witNames)
        {
            String message;
            _didDestroy = false;

            SetCursor(Cursors.Wait);
            _didDestroy = false;

            foreach (String witName in witNames)
            {
                WIManager.DestroyWITD(CurrentProject.Store.TeamProjectCollection.Uri.ToString(), CurrentProject.Name, witName, out message);
                if (!String.IsNullOrEmpty(message))
                {
                    MessageBox.Show(message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
                else
                {
                    _didDestroy = true;
                }
            }

            if (_didDestroy)
            {
                SyncReconnect();
                PopulateWorkItemTypes();
            }

            SetCursor(Cursors.Arrow);
        }

        /// <summary>
        /// Calls ImportWITD to import a new WITD from a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnImport_Click(object sender, RoutedEventArgs e)
        {
            Buttons(false);
            ImportWITD();
            Buttons(true);
        }

        /// <summary>
        /// Attempts to import the work item type definition from a file specified by the user.
        /// <para></para><para></para>
        /// Always performs validation of the WITD before importing. Never imports if validation fails.
        /// </summary>
        private void ImportWITD()
        {
            String fName;
            bool validated = false;

            _didImport = false;
            System.Windows.Forms.OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog();
            dialog.AddExtension = true;
            dialog.CheckFileExists = true;
            dialog.DefaultExt = "xml";
            dialog.Filter = "Work Item Type Definition File (*.xml)|*.xml";
            dialog.InitialDirectory = Environment.SpecialFolder.MyDocuments.ToString();
            dialog.Title = "Import Work Item Type Definition";
            
            try
            {
                ObscureMainWindow(null);

                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                        fName = dialog.FileName;
                        xml.Load(dialog.FileName);
                        //always do validation before import
                        try
                        {
                            WorkItemType.Validate(CurrentProject, xml.InnerXml);
                            validated = true;
                        }
                        catch (XmlException ex)
                        {
                            MessageBox.Show("Error validating WITD " + fName + ": " + ex.Message, "Validation error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                        catch (XmlSchemaValidationException sex)
                        {
                            MessageBox.Show("Error validating WITD " + fName + ": " + sex.Message, "Xml Schema validation error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }

                        if (validated && !chkValidateOnly.IsChecked.Value)
                        {
                            CurrentProject.WorkItemTypes.Import(xml.DocumentElement);
                            _didImport = true;
                            MessageBox.Show("Validation and import of WITD " + fName + " was successful.", "Validation and Import success", MessageBoxButton.OK, MessageBoxImage.Information);

                        }
                        else
                        {
                            if (validated) { MessageBox.Show("Validation of WITD " + fName + " was successful. No import was performed.", "Validation success", MessageBoxButton.OK, MessageBoxImage.Information); }
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error importing WITD " + dialog.FileName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    finally
                    {
                        if (_didImport)
                        {
                            SyncReconnect();
                            PopulateWorkItemTypes();
                        }

                        SetCursor(Cursors.Arrow);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Calls ExportWITD to export the selected WITD to a file.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExport_Click(object sender, RoutedEventArgs e)
        {
            if (lstWorkItemTypes.SelectedItem != null)
            {
                if (lstWorkItemTypes.SelectedItems.Count == 1)
                {
                    if (!String.IsNullOrEmpty(SelectedWIT))
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                        ExportWITD(SelectedWIT);
                        Buttons(true);
                        SetCursor(Cursors.Arrow);
                    }
                }
                else
                {
                    SetCursor(Cursors.Wait);
                    Buttons(false);
                    ArrayList wits = new ArrayList();
                    foreach (ListViewItem wit in lstWorkItemTypes.SelectedItems)
                    {
                        if (wit.IsSelected)
                        {
                            WorkItemType item = CurrentProject.WorkItemTypes[wit.Content.ToString()];
                            wits.Add(item);
                        }
                    }

                    ExportAllWITDs(wits);
                    
                    Buttons(true);
                    SetCursor(Cursors.Arrow);
                }
            }
            else
            {
                MessageBox.Show("You must select a WITD to export.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// Attempts to export the specified work item type to a file, named by the user.
        /// </summary>
        /// <param name="witName">The name of the work item type to export.</param>
        private void ExportWITD(String witName)
        {
            _didExport = false;
            System.Windows.Forms.SaveFileDialog dialog = new System.Windows.Forms.SaveFileDialog();
            dialog.AddExtension = true;
            dialog.DefaultExt = "xml";
            dialog.Filter = "Work Item Type Definition Files (*.xml)|*.xml";
            dialog.InitialDirectory = Environment.SpecialFolder.MyDocuments.ToString();
            dialog.OverwritePrompt = true;
            dialog.Title = "Export Work Item Type Definition to file";
            dialog.FileName = witName + ".xml";

            try
            {
                ObscureMainWindow(null);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                        System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                        xml = CurrentProject.WorkItemTypes[witName].Export(chkIncludeGlobalLists.IsChecked.Value);
                        xml.Save(dialog.FileName);
                        _didExport = true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error exporting " + witName + " to " + dialog.FileName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    finally
                    {
                        SetCursor(Cursors.Arrow);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Enables or disables the form's buttons.
        /// </summary>
        /// <param name="enable">True to enable all buttons. Otherwise false.</param>
        private void Buttons(bool enable)
        {
            btnClose.IsEnabled = enable;
            btnDestroyWIT.IsEnabled = enable;
            btnExport.IsEnabled = enable;
            btnImport.IsEnabled = enable;
            btnRename.IsEnabled = enable;
            btnRebuildcache.IsEnabled = enable;
            btnRefresh.IsEnabled = enable;
            btnAddCategory.IsEnabled = enable;
            btnAddWIT.IsEnabled = enable;
            btnChangeDefault.IsEnabled = enable;
            btnRemoveCategory.IsEnabled = enable;
            btnRemoveWIT.IsEnabled = enable;
            btnExportAllWITDs.IsEnabled = enable;
            btnExportCategories.IsEnabled = enable;
            chkIncludeGlobalLists.IsEnabled = enable;
            chkValidateOnly.IsEnabled = enable;
            chkOverwriteAll.IsEnabled = enable;
        }

        /// <summary>
        /// Attempts to refresh the cache for the current WorkItemStore and after 5 seconds, syncs the client to the cached data.
        /// <para></para>
        /// If the SyncReconnect fails, then a reconnect to the current project occurs to get the updated project information.
        /// </summary>
        private void SyncReconnect()
        {
            Reconnect();
            Sync();
            RebuildCache();
            PopulateWorkItemTypes(); 
            PopulateCategories(); 
        }

        /// <summary>
        /// Attempts to refresh the cache for the current WorkItemStore and after 5 seconds, syncs the client to the cached data.
        /// <para></para>
        /// If the SyncReconnect fails, then a reconnect to the current project occurs to get the updated project information.
        /// </summary>
        private void Sync()
        {
            SetCursor(Cursors.Wait);
            System.Threading.AutoResetEvent ev = new System.Threading.AutoResetEvent(false);

            CurrentProject.Store.RefreshCache();
            ev.WaitOne(5000);
            CurrentProject.Store.SyncToCache();
            SetCursor(Cursors.Arrow);
        }

        /// <summary>
        /// Reconnects to the project collection and work item store. This enables us to get the updated view of the store for the ui.
        /// </summary>
        /// <param name="project">The project that we want to refresh the view of.</param>
        private void Reconnect()
        {
            SetCursor(Cursors.Wait);
            TfsTeamProjectCollection collection = new TfsTeamProjectCollection(CurrentProject.Store.TeamProjectCollection.Uri);
            collection.EnsureAuthenticated();

            WorkItemStore store = (WorkItemStore)collection.GetService(typeof(WorkItemStore));
            CurrentProject = store.Projects[CurrentProject.Name];
            //project WorkItemTypes collection is changed, so reinstantiate
            CategoryManager = new WorkItemCategory(CurrentProject);
            SetCursor(Cursors.Arrow);
        }
                
        /// <summary>
        /// Calls the rebuildcache command of WitAdmin via the WorkItemTypedef object.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRebuildcache_Click(object sender, RoutedEventArgs e)
        {
            RebuildCache();
        }

        /// <summary>
        /// 
        /// </summary>
        private void RebuildCache()
        {
            WIManager.Refresh(CurrentProject.Store.TeamProjectCollection.Uri.ToString());
        }

        /// <summary>
        /// Calls the SyncReconnect method to recache and sync with the cache. Often does not actually recache, but nothing can be done about it.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRefresh_Click(object sender, RoutedEventArgs e)
        {
            SyncReconnect();
        }

        /// <summary>
        /// Exports the specified project's categories to a file. The user is prompted to choose a name and location for the file.
        /// </summary>
        /// <param name="project">The project from which to export the categories.</param>
        private void ExportCategories(Project project)
        {
            _didExport = false;
            System.Windows.Forms.SaveFileDialog dialog = new System.Windows.Forms.SaveFileDialog();
            dialog.AddExtension = true;
            dialog.DefaultExt = "xml";
            dialog.Filter = "Project Categories Definition Files (*.xml)|*.xml";
            dialog.InitialDirectory = Environment.SpecialFolder.MyDocuments.ToString();
            dialog.OverwritePrompt = true;
            dialog.Title = "Export Categories Definition to file";
            dialog.FileName = project.Name + "_Categories.xml";

            try
            {
                ObscureMainWindow(null);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                        System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                        xml = CurrentProject.Categories.Export();
                        xml.Save(dialog.FileName);
                        _didExport = true;
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Error exporting categories from " + project.Name + " to " + dialog.FileName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    finally
                    {
                        SetCursor(Cursors.Arrow);
                        Buttons(true);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Exports one or selected WITDs to individual files in the selected folder.
        /// <para></para><para></para>
        /// If the <see cref="chkOverwriteAll">Overwrite All checkbox</see> is checked, the WITD is saved to a file even if it already exists. Otherwise 
        /// the user is prompted to save it to a different name and/or location.
        /// <para></para><para></para>
        /// If the <see cref="chkIncludeGlobalLists">Include global lists checkbox</see> is checked, then the global list is embedded within the WITD file.
        /// </summary>
        /// <param name="wits">The project's entire collection of  <see cref="WorkItemType">WorkItemType</see> objects to export to files.</param>
        private void ExportAllWITDs(WorkItemTypeCollection wits)
        {
            String fileName = "";
            bool stopExport = false;
            int exportCount = 0;
            MessageBoxResult overwrite = MessageBoxResult.None;
            
            _didExport = false;
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.ShowNewFolderButton = true;

            try
            {
                ObscureMainWindow(null);

                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                        foreach (WorkItemType wit in wits)
                        {
                            System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                            xml = wit.Export(chkIncludeGlobalLists.IsChecked.Value);
                            fileName = System.IO.Path.Combine(dialog.SelectedPath, wit.Name + ".xml");
                            if (System.IO.File.Exists(fileName) && (!chkOverwriteAll.IsChecked.Value))
                            {
                                overwrite = MessageBox.Show(fileName + " already exists. Do you want to overwrite it with this definition?",
                                                    "Overwrite?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                                try
                                {
                                    switch (overwrite)
                                    {
                                        case MessageBoxResult.No:
                                            {
                                                ExportWITD(wit.Name);
                                                exportCount++;
                                                _didExport = true;
                                                break;
                                            }

                                        case MessageBoxResult.Cancel:
                                            {
                                                if (MessageBox.Show("Cancel export of remaining WITDs?", "Cancel all?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                                                {
                                                    stopExport = true;
                                                }
                                                break;
                                            }
                                        case MessageBoxResult.Yes:
                                            {
                                                xml.Save(fileName);
                                                exportCount++;
                                                _didExport = true;
                                                break;
                                            }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show("Error exporting WITD " + wit.Name + " to " + fileName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                                }

                            }
                            else
                            {
                                xml.Save(fileName);
                                exportCount++;
                                _didExport = true;
                            }
                            if (stopExport) { break; } //stop enumerating foreach
                        }
                    }

                    finally
                    {
                        SetCursor(Cursors.Arrow);
                        Buttons(true);
                    }

                    if (_didExport)
                    {
                        MessageBox.Show(exportCount.ToString() + " WITDs were exported.", "Exported " + exportCount.ToString() + "WITDs", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Exports one or selected WITDs to individual files in the selected folder.
        /// <para></para><para></para>
        /// If the <see cref="chkOverwriteAll">Overwrite All checkbox</see> is checked, the WITD is saved to a file even if it already exists. Otherwise 
        /// the user is prompted to save it to a different name and/or location.
        /// <para></para><para></para>
        /// If the <see cref="chkIncludeGlobalLists">Include global lists checkbox</see> is checked, then the global list is embedded within the WITD file.
        /// </summary>
        /// <param name="wits">A list of one or more <see cref="WorkItemType">WorkItemType</see> objects to export to files.</param>
        private void ExportAllWITDs(ArrayList wits)
        {
            String fileName = "";
            bool stopExport = false;
            int exportCount = 0;
            MessageBoxResult overwrite = MessageBoxResult.None;

            _didExport = false;
            System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
            dialog.ShowNewFolderButton = true;

            try
            {
                ObscureMainWindow(null);
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    try
                    {
                        SetCursor(Cursors.Wait);
                        Buttons(false);
                        foreach (WorkItemType wit in wits)
                        {
                            System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                            xml = wit.Export(chkIncludeGlobalLists.IsChecked.Value);
                            fileName = System.IO.Path.Combine(dialog.SelectedPath, wit.Name + ".xml");
                            if (System.IO.File.Exists(fileName) && (!chkOverwriteAll.IsChecked.Value))
                            {
                                overwrite = MessageBox.Show(fileName + " already exists. Do you want to overwrite it with this definition?",
                                                    "Overwrite?", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                                try
                                {
                                    switch (overwrite)
                                    {
                                        case MessageBoxResult.No:
                                            {
                                                ExportWITD(wit.Name);
                                                exportCount++;
                                                _didExport = true;
                                                break;
                                            }

                                        case MessageBoxResult.Cancel:
                                            {
                                                if (MessageBox.Show("Cancel export of remaining WITDs?", "Cancel all?", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
                                                {
                                                    stopExport = true;
                                                }
                                                break;
                                            }
                                        case MessageBoxResult.Yes:
                                            {
                                                xml.Save(fileName);
                                                exportCount++;
                                                _didExport = true;
                                                break;
                                            }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    MessageBox.Show("Error exporting WITD " + wit.Name + " to " + fileName + ": " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                                }

                            }
                            else
                            {
                                xml.Save(fileName);
                                exportCount++;
                                _didExport = true;
                            }
                            if (stopExport) { break; } //stop enumerating foreach
                        }
                    }

                    finally
                    {
                        SetCursor(Cursors.Arrow);
                        Buttons(true);
                    }

                    if (_didExport)
                    {
                        MessageBox.Show(exportCount.ToString() + " WITDs were exported.", "Exported " + exportCount.ToString() + "WITDs", MessageBoxButton.OK, MessageBoxImage.Information);
                    }
                }
            }
            finally
            {
                UnobscureMainWindow();
            }
        }

        /// <summary>
        /// Exports all WITDs to individual files in the selected folder. Calls <see cref="ExportAllWITDs">ExportAllWITDs() method</see>./>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExportAllWITDs_Click(object sender, RoutedEventArgs e)
        {
            if (lstWorkItemTypes.Items.Count > 0)
                ExportAllWITDs(CurrentProject.WorkItemTypes);
        }

        /// <summary>
        /// Exports all categories to a file in the selected folder. Calls <see cref="ExportCategories">ExportCategories() method</see>./>
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnExportCategories_Click(object sender, RoutedEventArgs e)
        {
            if (tvCategories.Items.Count > 0)
                ExportCategories(CurrentProject);
        }

        /// <summary>
        /// Places an opaque window over the current window to focus the user's attention on the new form about to open and claim focus.
        /// </summary>
        private void ObscureMainWindow(Window newWindow)
        {
            Topmost = false;
            toolWindow = newWindow;
            if (newWindow != null) newWindow.Topmost = true;
            hider.Height = this.Height;
            hider.Width = this.Width;
            hider.Top = this.Top;
            hider.Left = this.Left;
            hider.Cursor = Cursors.Wait;
            hider.Show();
        }

        /// <summary>
        /// Hides the opaque window without destroying it, making the current form the focus once again.
        /// </summary>
        private void UnobscureMainWindow()
        {
            hider.Hide();
            toolWindow = this;
            this.Topmost = true;
            this.Focus();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Activated(object sender, EventArgs e)
        {
            if (hider.Visibility == System.Windows.Visibility.Visible)
            {
                hider.Topmost = true;
                if (toolWindow != null)
                {
                    toolWindow.Topmost = true;
                    toolWindow.Focus();
                }
            }
        }
    }
}
